﻿using System;
using System.Reflection;

namespace MSOffice.Outlook
{
    public enum ItemType
    {
        AppointmentItem,
        ContactItem,
        DistributionListItem,
        JournalItem,
        MailItem,
        NoteItem,
        PostItem,
        TaskItem
    }

    public class Application
    {
        private readonly object outlook = Activator.CreateInstance(Type.GetTypeFromProgID("Outlook.Application"));
        private readonly object ns = null;
        private ItemCollection<Folder> folders = null;

        public Application()
        {
            ns = InvokeMethod(outlook, "GetNamespace", new object[] { "MAPI" });
        }

        public ItemCollection<Folder> Folders
        {
            get
            {
                if (folders == null)
                {
                    object fs = GetProperty(ns, "Folders");

                    folders = new ItemCollection<Folder>(fs, ns, "Folders");
                }

                return folders;
            }
        }

        public static object GetProperty(object obj, string name)
        {
            return obj.GetType().InvokeMember(name, BindingFlags.GetProperty, null, obj, null);
        }

        public static object GetProperty(object obj, string name, int i)
        {
            return obj.GetType().InvokeMember(name, BindingFlags.GetProperty, null, obj, new object[] { i });
        }

        public static object InvokeMethod(object obj, string name)
        {
            return obj.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, obj, null);
        }

        public static object InvokeMethod(object obj, string name, object[] _params)
        {
            return obj.GetType().InvokeMember(name, BindingFlags.InvokeMethod, null, obj, _params);
        }
    }

    public class ItemCollection<T> where T: Item, new()
    {
        private readonly object items = null;
        private readonly object items2 = null;
        private readonly string prop = null;

        public ItemCollection(object items, object items2, string prop)
        {
            this.items = items;
            this.items2 = items2;
            this.prop = prop;
        }

        public T this[int i]
        {
            get
            {
                object f = Application.GetProperty(items2, prop, i);

                T t = new T();
                t.Init(f);

                return t;
            }
        }

        public int Count
        {
            get
            {
                object res = Application.GetProperty(items, "Count");

                return (int)res;
            }
        }
    }

    public class Item
    {
        public object Obj { get; private set; }

        public void Init(object obj)
        {
            this.Obj = obj;
        }
    }

    public class Folder : Item
    {
        private ItemCollection<Folder> folders = null;
        private ItemCollection<MailItem> mailItems = null;

        public string Name
        {
            get
            {
                object res = Application.GetProperty(Obj, "Name");

                return (string)res;
            }
        }

        public string FullFolderPath
        {
            get
            {
                object res = Application.GetProperty(Obj, "FullFolderPath");

                return (string)res;
            }
        }

        public ItemCollection<Folder> Folders
        {
            get
            {
                if (folders == null)
                {
                    object fs = Application.GetProperty(Obj, "Folders");

                    folders = new ItemCollection<Folder>(fs, Obj, "Folders");
                }

                return folders;
            }
        }

        public ItemCollection<MailItem> MailItems
        {
            get
            {
                if (mailItems == null)
                {
                    object mi = Application.GetProperty(Obj, "Items");

                    mailItems = new ItemCollection<MailItem>(mi, Obj, "Items");
                }

                return mailItems;
            }
        }

        public ItemType DefaultItemType
        {
            get
            {
                object tmp = Application.GetProperty(Obj, "DefaultItemType");

                ItemType res;

                switch ((int)tmp)
                {
                    case 0: res = ItemType.MailItem; break;
                    case 1: res = ItemType.AppointmentItem; break;
                    case 2: res = ItemType.ContactItem; break;
                    case 3: res = ItemType.TaskItem; break;
                    case 4: res = ItemType.JournalItem; break;
                    case 5: res = ItemType.NoteItem; break;
                    case 6: res = ItemType.PostItem; break;
                    case 7: res = ItemType.DistributionListItem; break;
                    default: throw new Exception("Не определённый тип элемента");
                }

                return res;
            }
        }
    }

    public class MailItem : Item
    {
        public string Subject
        {
            get
            {
                object res = Application.GetProperty(Obj, "Subject");

                return (string)res;
            }
        }

        public string SenderName
        {
            get
            {
                object res = Application.GetProperty(Obj, "SenderName");

                return (string)res;
            }
        }

        public DateTime ReceivedTime
        {
            get
            {
                object res = Application.GetProperty(Obj, "ReceivedTime");

                return (DateTime)res;
            }
        }

        public string Body
        {
            get
            {
                object res = Application.GetProperty(Obj, "Body");

                return (string)res;
            }
        }

        public string ReceivedByName
        {
            get
            {
                object res = Application.GetProperty(Obj, "ReceivedByName");

                return (string)res;
            }
        }

        public string BCC
        {
            get
            {
                object res = Application.GetProperty(Obj, "BCC");

                return (string)res;
            }
        }

        public string CC
        {
            get
            {
                object res = Application.GetProperty(Obj, "CC");

                return (string)res;
            }
        }

        public string To
        {
            get
            {
                object res = Application.GetProperty(Obj, "To");

                return (string)res;
            }
        }

        public void Move(Folder f)
        {
            Application.InvokeMethod(Obj, "Move", new object[] { f.Obj });
        }

        public void Delete()
        {
            Application.InvokeMethod(Obj, "Delete");
        }
    }
}